package com.curry.apiprovider.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.curry.apiprovider.crawler.task.ScheduledJob;
import com.curry.apiprovider.exception.QuartzJobException;
import com.curry.apiprovider.generator.mapper.TQuartzInfoMapper;
import com.curry.apiprovider.response.ResultCode;
import com.curry.apiprovider.service.ScheduleJobService;
import com.curry.apiprovider.util.DateUtils;
import com.curry.apiprovider.util.StringUtils;
import com.curry.livehelper.entity.domain.TQuartzInfo;
import com.curry.livehelper.entity.domain.TaskEntity;
import io.swagger.models.auth.In;
import org.apache.ibatis.session.RowBounds;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
public class ScheduleJobServiceImpl implements ScheduleJobService {
    @Autowired
    private Scheduler scheduler;

    @Autowired
    TQuartzInfoMapper tQuartzInfoMapper;
    private Logger logger = LoggerFactory.getLogger(ScheduleJobServiceImpl.class);

    /**
     * 添加定时任务
     *
     * @param tQuartzInfo
     * @throws ClassNotFoundException
     * @throws SchedulerException
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    @Transactional
    public void add(TQuartzInfo tQuartzInfo) throws ClassNotFoundException, QuartzJobException,
            SchedulerException {
        JobDetail jobDetail = JobBuilder.newJob(ScheduledJob.class)
                .withIdentity(tQuartzInfo.getTaskDescript(), tQuartzInfo.getGroupName())
                .usingJobData("className", tQuartzInfo.getClassName())
                .usingJobData("methodName", tQuartzInfo.getMethodName())
                .build();
        jobDetail.getJobDataMap().put("TQuartzInfo", tQuartzInfo);

        // 表达式调度构建器（可判断创建SimpleScheduleBuilder）

        if (!tQuartzInfo.getCronExpress().startsWith("0")) {
            throw new QuartzJobException("定时周期必须0开头,代表每天执行一次");
        }
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder
                .cronSchedule(tQuartzInfo.getCronExpress());

        // 按新的cronExpression表达式构建一个新的trigger

        TQuartzInfo quartzInfo = new TQuartzInfo();
        quartzInfo.setTaskDescript(tQuartzInfo.getTaskDescript());
        quartzInfo.setGroupName(tQuartzInfo.getGroupName());
        TQuartzInfo selectOne = tQuartzInfoMapper.selectOne(quartzInfo);
        if (selectOne == null) {
            if (StringUtils.isEmpty(quartzInfo.getStatus())) {
                //默认是立刻执行
                tQuartzInfo.setStatus("1");
            }
            tQuartzInfo.setCreateTime(DateUtils.getCurrentDate("yyyy-MM-dd HH:mm"));
            tQuartzInfoMapper.insert(tQuartzInfo);
            logger.warn("添加一个定时任务 " + tQuartzInfo.getTaskDescript());
            CronTrigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity(tQuartzInfo.getTaskDescript(), tQuartzInfo.getGroupName())
                    .withSchedule(scheduleBuilder).build();
            if (tQuartzInfo.getStatus().equals("1")) {
                scheduler.scheduleJob(jobDetail, trigger);
            }
        } else {
            throw new QuartzJobException(ResultCode.RESULT_EXIST_JOB_ERROR.getMessage());
        }
    }

    /**
     * 添加临时任务重启任务
     * 针对于任务列表中没有这个任务的情况
     *
     * @param tQuartzInfo
     */
    public void addTempTaskToRestart(TQuartzInfo tQuartzInfo)
            throws QuartzJobException, SchedulerException {
        JobDetail jobDetail = JobBuilder.newJob(ScheduledJob.class)
                .withIdentity(tQuartzInfo.getTaskDescript(), tQuartzInfo.getGroupName())
                .usingJobData("className", tQuartzInfo.getClassName())
                .usingJobData("methodName", tQuartzInfo.getMethodName())
                .build();
        logger.warn("tQuartzInfo " + tQuartzInfo.toString());
        jobDetail.getJobDataMap().put("TQuartzInfo", tQuartzInfo);

        // 表达式调度构建器（可判断创建SimpleScheduleBuilder）

        if (!tQuartzInfo.getCronExpress().startsWith("0")) {
            throw new QuartzJobException("定时周期必须0开头,代表每天执行一次");
        }
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder
                .cronSchedule(tQuartzInfo.getCronExpress());
        CronTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(tQuartzInfo.getTaskDescript(), tQuartzInfo.getGroupName())
                .withSchedule(scheduleBuilder).build();
        TQuartzInfo tquartzInfo = new TQuartzInfo();
        tquartzInfo.setStatus("1");
        tQuartzInfo.setGroupName(tquartzInfo.getGroupName());
        tquartzInfo.setTaskDescript(tQuartzInfo.getTaskDescript());
        tQuartzInfoMapper.updateJobTaskStatu(tquartzInfo);
        scheduler.scheduleJob(jobDetail, trigger);
    }

    /**
     * 获取所有JobDetail
     *
     * @return 结果集合
     */
    public List<JobDetail> getJobs() {
        try {
            GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
            Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
            List<JobDetail> jobDetails = new ArrayList<JobDetail>();
            for (JobKey key : jobKeys) {
                jobDetails.add(scheduler.getJobDetail(key));
            }
            return jobDetails;
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return null;
    }

    public List<TaskEntity> getAllTask(Integer page, Integer limit) {
        Map<String, Integer> params = new HashMap<>();
        params.put("pageSize", page - 1);
        params.put("pageIndex", limit);
        List<TaskEntity> tQuartzInfos = tQuartzInfoMapper.getTaskList(params);
        return tQuartzInfos;
    }

    /**
     * 判断是否存在定时任务在任务队列中
     *
     * @return
     */
    public boolean hasContainerTask(List<TQuartzInfo> tQuartzInfoList, TQuartzInfo tQuartzInfo) {
        boolean isExist = false;
        for (TQuartzInfo tQuartzInfo1 : tQuartzInfoList) {
            if (tQuartzInfo1.getGroupName().equals(tQuartzInfo.getGroupName())
                    && tQuartzInfo1.getTaskDescript().equals(tQuartzInfo.getTaskDescript())) {
                isExist = true;
                break;
            }
        }
        return isExist;
    }

    /**
     * 获取所有计划中的任务
     *
     * @return 结果集合
     */
    public List<TQuartzInfo> getAllScheduleJob() {
        List<TQuartzInfo> scheduleEntityList = new ArrayList<TQuartzInfo>();
        GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
        try {
            Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
            for (JobKey jobKey : jobKeys) {
                List<? extends Trigger> triggers = scheduler
                        .getTriggersOfJob(jobKey);
                for (Trigger trigger : triggers) {
                    TQuartzInfo tQuartzInfo = new TQuartzInfo();
                    tQuartzInfo.setTaskDescript(jobKey.getName());
                    tQuartzInfo.setGroupName(jobKey.getGroup());
                    Trigger.TriggerState triggerState = scheduler
                            .getTriggerState(trigger.getKey());
                    tQuartzInfo.setStatus(triggerState.name());
                    // 获取要执行的定时任务类名


                    JobDetail jobDetail = scheduler.getJobDetail(jobKey);
                    //获取class及method
                    JobDataMap dataMap = jobDetail.getJobDataMap();
                    tQuartzInfo.setClassName(dataMap.getString("className"));
                    tQuartzInfo.setMethodName(dataMap.getString("methodName"));

                    //TQuartzInfo.setClassName(jobDetail.getJobClass().getName());
                    // 判断trigger

                    if (trigger instanceof SimpleTrigger) {
                        SimpleTrigger simple = (SimpleTrigger) trigger;
                        tQuartzInfo.setCronExpress("重复次数:"
                                + (simple.getRepeatCount() == -1 ? "无限"
                                : simple.getRepeatCount()) + ",重复间隔:"
                                + (simple.getRepeatInterval() / 1000L));
                        tQuartzInfo.setDescription(simple.getDescription());
                    }
                    if (trigger instanceof CronTrigger) {
                        CronTrigger cron = (CronTrigger) trigger;
                        tQuartzInfo.setCronExpress(cron.getCronExpression());
                        tQuartzInfo
                                .setDescription(cron.getDescription() == null ? ("触发器:" + trigger
                                        .getKey()) : cron.getDescription());
                    }
                    scheduleEntityList.add(tQuartzInfo);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return scheduleEntityList;
    }

    /**
     * 获取所有运行中的任务
     *
     * @return 结果集合
     */
    public List<TQuartzInfo> getAllRuningScheduleJob() {
        List<TQuartzInfo> scheduleEntityList = null;
        try {
            List<JobExecutionContext> executingJobs = scheduler
                    .getCurrentlyExecutingJobs();
            scheduleEntityList = new ArrayList<TQuartzInfo>(executingJobs.size());
            for (JobExecutionContext executingJob : executingJobs) {
                TQuartzInfo tQuartzInfo = new TQuartzInfo();
                JobDetail jobDetail = executingJob.getJobDetail();
                JobKey jobKey = jobDetail.getKey();
                Trigger trigger = executingJob.getTrigger();
                tQuartzInfo.setTaskDescript(jobKey.getName());
                tQuartzInfo.setGroupName(jobKey.getGroup());
                // TQuartzInfo.setDescription("触发器:" + trigger.getKey());


                Trigger.TriggerState triggerState = scheduler
                        .getTriggerState(trigger.getKey());
                tQuartzInfo.setStatus(triggerState.name());
                // 获取要执行的定时任务类名


                tQuartzInfo.setClassName(jobDetail.getJobClass().getName());
                // 判断trigger


                if (trigger instanceof SimpleTrigger) {
                    SimpleTrigger simple = (SimpleTrigger) trigger;
                    tQuartzInfo.setCronExpress("重复次数:"
                            + (simple.getRepeatCount() == -1 ? "无限" : simple
                            .getRepeatCount()) + ",重复间隔:"
                            + (simple.getRepeatInterval() / 1000L));
                    tQuartzInfo.setDescription(simple.getDescription());
                }
                if (trigger instanceof CronTrigger) {
                    CronTrigger cron = (CronTrigger) trigger;
                    tQuartzInfo.setCronExpress(cron.getCronExpression());
                    tQuartzInfo.setDescription(cron.getDescription());
                }
                scheduleEntityList.add(tQuartzInfo);
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return scheduleEntityList;
    }

    /**
     * 获取所有的触发器
     *
     * @return 结果集合
     */
    public List<TQuartzInfo> getTriggersInfo() {
        try {
            GroupMatcher<TriggerKey> matcher = GroupMatcher.anyTriggerGroup();
            Set<TriggerKey> Keys = scheduler.getTriggerKeys(matcher);
            List<TQuartzInfo> triggers = new ArrayList<TQuartzInfo>();

            for (TriggerKey key : Keys) {
                Trigger trigger = scheduler.getTrigger(key);
                TQuartzInfo tQuartzInfo = new TQuartzInfo();
                tQuartzInfo.setTaskDescript(trigger.getJobKey().getName());
                tQuartzInfo.setGroupName(trigger.getJobKey().getGroup());
                tQuartzInfo.setStatus(scheduler.getTriggerState(key) + "");
                if (trigger instanceof SimpleTrigger) {
                    SimpleTrigger simple = (SimpleTrigger) trigger;
                    tQuartzInfo.setCronExpress("重复次数:"
                            + (simple.getRepeatCount() == -1 ? "无限" : simple
                            .getRepeatCount()) + ",重复间隔:"
                            + (simple.getRepeatInterval() / 1000L));
                    tQuartzInfo.setDescription(simple.getDescription());
                }
                if (trigger instanceof CronTrigger) {
                    CronTrigger cron = (CronTrigger) trigger;
                    tQuartzInfo.setCronExpress(cron.getCronExpression());
                    tQuartzInfo.setDescription(cron.getDescription());
                }
                triggers.add(tQuartzInfo);
            }
            return triggers;
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 暂停任务
     *
     * @throws SchedulerException
     */
    public void stopJob(Integer taskId) throws SchedulerException, QuartzJobException {
        TQuartzInfo info = tQuartzInfoMapper.selectById(taskId);
        String name = info.getTaskDescript();
        String group = info.getGroupName();
        JobKey key = new JobKey(name, info.getGroupName());
        TQuartzInfo tQuartzInfo = new TQuartzInfo();
        tQuartzInfo.setTaskDescript(name);
        tQuartzInfo.setGroupName(group);
        TQuartzInfo quartzInfo = tQuartzInfoMapper.selectOne(tQuartzInfo);
        if (quartzInfo != null) {
            TQuartzInfo stopQuartz = new TQuartzInfo();
            stopQuartz.setStatus("0");
            stopQuartz.setTaskDescript(quartzInfo.getTaskDescript());
            stopQuartz.setGroupName(quartzInfo.getGroupName());
            tQuartzInfoMapper.updateJobTaskStatu(stopQuartz);
            logger.warn("停止一个定时任务 " + name);
            scheduler.pauseJob(key);
        } else {
            throw new QuartzJobException(ResultCode.RESULT_NOT_EXIST_JOB_ERROR.getMessage());
        }
    }

    /**
     * 恢复任务
     *
     * @param name  任务名
     * @param group 任务组
     * @throws SchedulerException
     */
    public void restartJob(String name, String group) throws SchedulerException {
        JobKey key = new JobKey(name, group);
        logger.warn("restartJob " + name);
        EntityWrapper<TQuartzInfo> entityWrapper = new EntityWrapper<>(new TQuartzInfo());
        entityWrapper.where("taskDescript={0}", name).and("groupName={0}", group);
        TQuartzInfo tQuartzInfo = new TQuartzInfo();
        tQuartzInfo.setStatus("1");
        tQuartzInfoMapper.update(tQuartzInfo, entityWrapper);
        scheduler.resumeJob(key);
    }

    /**
     * 立马执行一次任务
     *
     * @param name  任务名
     * @param group 任务组
     * @throws SchedulerException
     */
    public void startNowJob(String name, String group) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(name, group);
        scheduler.triggerJob(jobKey);
        logger.warn("startNowJob " + name);

    }

    /**
     * 执行一次的任务
     *
     * @param tQuartzInfo
     * @throws SchedulerException
     */
    public void immediateTask(TQuartzInfo tQuartzInfo) throws SchedulerException {
        JobDetail jobDetail = JobBuilder.newJob(ScheduledJob.class)
                .withIdentity(tQuartzInfo.getTaskDescript(), tQuartzInfo.getGroupName())
                .usingJobData("className", tQuartzInfo.getClassName())
                .usingJobData("methodName", tQuartzInfo.getMethodName())
                .build();
        jobDetail.getJobDataMap().put("TQuartzInfo", tQuartzInfo);
        SimpleTrigger simpleTrigger = TriggerBuilder.newTrigger()
                .withIdentity(tQuartzInfo.getTaskDescript(), tQuartzInfo.getGroupName())
                .startAt(new Date())
                .withSchedule(
                        SimpleScheduleBuilder.simpleSchedule()
                                .withIntervalInSeconds(5)
                                .withRepeatCount(0))//重复执行的次数，因为加入任务的时候马上执行了，所以不需要重复，否则会多一次。
                .build();
        scheduler.scheduleJob(jobDetail, simpleTrigger);
    }

    /**
     * 删除任务
     *
     * @param name  任务名
     * @param group 任务组
     * @throws SchedulerException
     */
    public void delJob(String name, String group) throws SchedulerException {
        JobKey key = new JobKey(name, group);
        logger.warn("delJob " + name);
        EntityWrapper<TQuartzInfo> entityWrapper = new EntityWrapper<>(new TQuartzInfo());
        entityWrapper.where("taskDescript={0}", name).and("groupName={0}", group);
        tQuartzInfoMapper.delete(entityWrapper);
        scheduler.deleteJob(key);
    }

    /**
     * 修改触发器时间
     *
     * @param name  任务名
     * @param group 任务组
     * @param cron  cron表达式
     * @throws SchedulerException
     */
    public void modifyTrigger(String name, String group, String cron) throws SchedulerException {
        TriggerKey key = TriggerKey.triggerKey(name, group);
        // Trigger trigger = scheduler.getTrigger(key);


        CronTrigger newTrigger = (CronTrigger) TriggerBuilder.newTrigger()
                .withIdentity(key)
                .withSchedule(CronScheduleBuilder.cronSchedule(cron))
                .build();
        EntityWrapper<TQuartzInfo> entityWrapper = new EntityWrapper<>(new TQuartzInfo());
        entityWrapper.where("taskDescript={0}", name).and("groupName={0}", group);
        TQuartzInfo tQuartzInfo = new TQuartzInfo();
        tQuartzInfo.setCronExpress(cron);
        tQuartzInfoMapper.update(tQuartzInfo, entityWrapper);
        logger.warn("modifyTrigger " + name);
        scheduler.rescheduleJob(key, newTrigger);
    }

    /**
     * 暂停调度器
     *
     * @throws SchedulerException
     */
    public void stopScheduler() throws SchedulerException {
        if (!scheduler.isInStandbyMode()) {
            scheduler.standby();
        }
    }
}
